package cn.zyq.ykb.system.pay.core.client.impl.alipay;


import cn.hutool.core.io.IoUtil;
import cn.zyq.ykb.system.config.ali.AliAppProperties;
import cn.zyq.ykb.system.config.ali.AliH5Properties;
import cn.zyq.ykb.system.exception.BusinessException;
import cn.zyq.ykb.system.pay.config.PayAliProperties;
import cn.zyq.ykb.system.pay.core.client.PayClient;
import cn.zyq.ykb.system.pay.core.client.PayClientConfig;
import cn.zyq.ykb.system.pay.core.client.impl.PayClientFactoryImpl;
import cn.zyq.ykb.system.pay.core.enums.PayChannelEnum;
import com.alipay.api.AlipayClient;
import com.alipay.api.AlipayConfig;
import com.alipay.api.DefaultAlipayClient;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import javax.validation.ConstraintViolation;
import javax.validation.Validator;
import javax.validation.constraints.NotBlank;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Set;

// TODO 芋艿：参数校验

/**
 * 支付宝的 PayClientConfig 实现类
 * 属性主要来自 {@link AlipayConfig} 的必要属性
 *
 * @author 芋道源码
 */
@Slf4j
@Data
public class AlipayPayClientConfig implements PayClientConfig {

    /**
     * 网关地址 - 线上
     */
    public static final String SERVER_URL_PROD = "https://openapi.alipay.com/gateway.do";
    /**
     * 网关地址 - 沙箱
     */
    public static final String SERVER_URL_SANDBOX = "https://openapi.alipaydev.com/gateway.do";

    /**
     * 公钥类型 - 公钥模式
     */
    public static final Integer MODE_PUBLIC_KEY = 1;
    /**
     * 公钥类型 - 证书模式
     */
    public static final Integer MODE_CERTIFICATE = 2;

    /**
     * 签名算法类型 - RSA
     */
    public static final String SIGN_TYPE_DEFAULT = "RSA2";

    /**
     * 网关地址
     * 1. {@link #SERVER_URL_PROD}
     * 2. {@link #SERVER_URL_SANDBOX}
     */
    @NotBlank(message = "网关地址不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
    private String serverUrl;

    /**
     * 开放平台上创建的应用的 ID
     */
    @NotBlank(message = "开放平台上创建的应用的 ID不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
    private String appId;

    /**
     * 签名算法类型，推荐：RSA2
     * <p>
     * {@link #SIGN_TYPE_DEFAULT}
     */
    // @NotBlank(message = "签名算法类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
    private String signType;

    /**
     * 公钥类型
     * 1. {@link #MODE_PUBLIC_KEY} 情况，privateKey + alipayPublicKey
     * 2. {@link #MODE_CERTIFICATE} 情况，appCertContent + alipayPublicCertContent + rootCertContent
     */
    // @NotNull(message = "公钥类型不能为空", groups = {ModePublicKey.class, ModeCertificate.class})
    private Integer mode;

    // ========== 公钥模式 ==========
    /**
     * 商户私钥
     */
    // @NotBlank(message = "商户私钥不能为空", groups = {ModePublicKey.class})
    private String privateKey;

    /**
     * 支付宝公钥字符串
     */
    // @NotBlank(message = "支付宝公钥字符串不能为空", groups = {ModePublicKey.class})
    private String alipayPublicKey;

    // ========== 证书模式 ==========
    /**
     * 指定商户公钥应用证书内容字符串
     */
    // @NotBlank(message = "指定商户公钥应用证书内容不能为空", groups = {ModeCertificate.class})
    private String appCertContent;
    /**
     * 指定支付宝公钥证书内容字符串
     */
    // @NotBlank(message = "指定支付宝公钥证书内容不能为空", groups = {ModeCertificate.class})
    private String alipayPublicCertContent;
    /**
     * 指定根证书内容字符串
     */
    // @NotBlank(message = "指定根证书内容字符串不能为空", groups = {ModeCertificate.class})
    private String rootCertContent;

    public interface ModePublicKey {
    }

    public interface ModeCertificate {
    }

    @Override
    public Set<ConstraintViolation<PayClientConfig>> verifyParam(Validator validator) {
        return validator.validate(this,
                MODE_PUBLIC_KEY.equals(this.getMode()) ? ModePublicKey.class : ModeCertificate.class);
    }

    /**
     * H5支付渠道
     *
     * @return
     */
    public static PayClient getH5PayClient() {
        // 创建配置
        AlipayPayClientConfig config = new AlipayPayClientConfig();
        config.setAppId(AliH5Properties.appId);
        config.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD);
        config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
        config.setPrivateKey(PayAliProperties.privateKey);
        config.setAlipayPublicKey(PayAliProperties.alipayPublicKey);
        config.setMode(MODE_CERTIFICATE);
        try {
            config.setAppCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.appCertContent)));
            config.setAlipayPublicCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.alipayPublicCertContent)));
            config.setRootCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.rootCertContent)));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 创建客户端
        Integer channelId = PayChannelEnum.ALIPAY_WAP.getChannelId();
        PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
        payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_WAP.getCode(), config);
        return payClientFactory.getPayClient(channelId);
    }

    /**
     * 安卓app渠道
     *
     * @return
     */
    public static PayClient getAppPayAndroidClient() {
        // 创建配置
        AlipayPayClientConfig config = new AlipayPayClientConfig();
        config.setAppId(AliAppProperties.androidAppId);
        config.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD);
        config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
        config.setPrivateKey(PayAliProperties.privateKey);
        config.setAlipayPublicKey(PayAliProperties.alipayPublicKey);
        config.setMode(MODE_CERTIFICATE);
        try {
            config.setAppCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.appCertContent)));
            config.setAlipayPublicCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.alipayPublicCertContent)));
            config.setRootCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.rootCertContent)));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        // 创建客户端
        Integer channelId = PayChannelEnum.ALIPAY_APP_ANDROID.getChannelId();
        PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
        payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_APP_ANDROID.getCode(), config);
        return payClientFactory.getPayClient(channelId);
    }

    /**
     * 苹果APP渠道
     *
     * @return
     */
    public static PayClient getAppPayIosClient() {
        // 创建配置
        log.info("私钥：" + PayAliProperties.privateKey);
        log.info("公钥：" + PayAliProperties.alipayPublicKey);
        AlipayPayClientConfig config = new AlipayPayClientConfig();
        config.setAppId(AliAppProperties.iosAppId);
        config.setServerUrl(AlipayPayClientConfig.SERVER_URL_PROD);
        config.setSignType(AlipayPayClientConfig.SIGN_TYPE_DEFAULT);
        config.setPrivateKey(PayAliProperties.privateKey);
        config.setAlipayPublicKey(PayAliProperties.alipayPublicKey);
        config.setMode(MODE_CERTIFICATE);

        try {
            config.setAppCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.appCertContent)));
            config.setAlipayPublicCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.alipayPublicCertContent)));
            config.setRootCertContent(IoUtil.readUtf8(new FileInputStream(PayAliProperties.rootCertContent)));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }

        // 创建客户端
        Integer channelId = PayChannelEnum.ALIPAY_APP_IOS.getChannelId();
        PayClientFactoryImpl payClientFactory = new PayClientFactoryImpl();
        payClientFactory.createOrUpdatePayClient(channelId, PayChannelEnum.ALIPAY_APP_IOS.getCode(), config);
        return payClientFactory.getPayClient(channelId);
    }

    public static AlipayClient getAlipayClient(String appid) throws Exception {
        AlipayConfig alipayConfig = new AlipayConfig();
        alipayConfig.setAppId(appid);
        alipayConfig.setPrivateKey(PayAliProperties.privateKey);
        alipayConfig.setAlipayPublicKey(PayAliProperties.alipayPublicKey);
        AlipayClient alipayClient = new DefaultAlipayClient(alipayConfig);
        return alipayClient;
    }

    public static PayClient getPayClientByChannelId(Integer channelId) {
        if (PayChannelEnum.ALIPAY_PC.getChannelId().equals(channelId)) {
            // return getH5PayClient();
            throw new BusinessException("暂未开通该渠道");
        } else if (PayChannelEnum.ALIPAY_WAP.getChannelId().equals(channelId)) {
            return getH5PayClient();
        } else if (PayChannelEnum.ALIPAY_APP_ANDROID.getChannelId().equals(channelId)) {
            return getAppPayAndroidClient();
        } else if (PayChannelEnum.ALIPAY_APP_IOS.getChannelId().equals(channelId)) {
            return getAppPayIosClient();
        } else if (PayChannelEnum.ALIPAY_QR.getChannelId().equals(channelId)) {
            // return getPubPayClient();
            throw new BusinessException("暂未开通该渠道");
        } else {
            throw new BusinessException("没有获取到准确的渠道");
        }
    }
}
